package IA.Bicing;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

import aima.search.framework.HeuristicFunction;
import aima.search.framework.Problem;
import aima.search.framework.Search;
import aima.search.framework.SearchAgent;
import aima.search.framework.SuccessorFunction;
import aima.search.informed.HillClimbingSearch;
import aima.search.informed.SimulatedAnnealingSearch;

public class main {

	static int E = 25;
	static int B = 1250;
	static int F = 5;

	// Parametres busc. local
	static int heuristic = 1; // max. beneficis (0), max. ben. i min. costos(1)
	static int tipus_busqueda = 0; //hc (0), sa (1)
	static int assig_inicial = 1; //aleatori (0), greedy (1)
	static int demanda = 0; //equilibrada (0), hora punta(1)
    static int operadors = 0;
	
    //int reco_total = 0; //recorregut total de les assig. (?)
    
    // Parametres sa
	static int steps = 7000;
	static int stIter =500;
	static int k = 1;
	static double lambda = 0.01;
	
	public static void main(String[] args) throws IOException {
	        InputStreamReader isr = new InputStreamReader(System.in);
	        BufferedReader br = new BufferedReader (isr);
	        
	        
	        System.out.println("Introdueix el nombre d'estacions (E):");
	        E =  Integer.parseInt (br.readLine());
	        System.out.println("Introdueix el nombre de bicicletes (B):");
	        B =  Integer.parseInt (br.readLine());
	        System.out.println("Introdueix el nombre de furgonetes (F):");
	        F =  Integer.parseInt (br.readLine());
	        
	        System.out.println("Introdueix el tipus d'estat inicial");
	        System.out.println("    0 -Aleatori    1 -Greedy    2 -Buit");
	        assig_inicial =  Integer.parseInt (br.readLine());
	        
	        
	        System.out.println("Introdueix el tipus de funcio heuristica");
	        System.out.println("    0 -Maximitzar beneficis     1 -Max. beneficis i Min. costos");
	        heuristic =  Integer.parseInt (br.readLine());
	        
	        System.out.println("Introdueix l'algorisme");
	        System.out.println("    0 -Hill Climbing     1 -Simulated Annealing");
	        tipus_busqueda =  Integer.parseInt (br.readLine());
	        System.out.println("Introdueix els operadors");
	        System.out.println("    0 -Normal     1 -Swap");
	        operadors =  Integer.parseInt (br.readLine());
	        
	        System.out.println("Introdueix la distribucio");
	        System.out.println("    0 -Equilibrada     1 -Hora punta");
	        demanda =  Integer.parseInt (br.readLine());
	        if (tipus_busqueda == 1){
	            System.out.println("Parametres Simulated Annealing");
	            System.out.println("Introdueix el nombre d'iteracions");
	            steps =  Integer.parseInt (br.readLine());
	            System.out.println("Introdueix el nombre d'iteracions per cada pas de temperatura");
	            stIter =  Integer.parseInt (br.readLine());
	            System.out.println("Introdueix la k");
	            k =  Integer.parseInt (br.readLine());
	            System.out.println("Introdueix la lambda");
	            lambda =  Integer.parseInt (br.readLine());
	        }     
	        
	        bicingMapBoard bMB = new bicingMapBoard(E, B, F, demanda);
	        
	        long temps_inici = System.currentTimeMillis();    
	        if(assig_inicial == 0){
	        	bMB.estatInicialAleatori();
	        } else if(assig_inicial == 1){
	        	bMB.estatInicialGreedy();
	        }else{
	        	// FURGONETES PARADES
	        }
	        
	        if(tipus_busqueda == 0){
	        	HillClimbingSearch(bMB);
	        } else if(tipus_busqueda == 1){
	        	SimulatedAnnealingSearch(bMB);
	        }
	        
	        long temps_execucio = System.currentTimeMillis() - temps_inici;
	        System.out.println("TEMPS EXEC: "+ temps_execucio);
	}
	
	
    private static void HillClimbingSearch(bicingMapBoard mp) {
		try {
			Problem problem;
			
			HeuristicFunction bHF = null;
			if(heuristic == 0)	bHF = new bicingHeuristicFunction();
			else				bHF = new bicingHeuristicFunction2();
			
			SuccessorFunction bSF = null;
			if(operadors == 0)	bSF = new bicingSuccessorFunction();
			else				bSF = new bicingSuccessorFunction2();
					
			
        	
        	problem = new Problem(mp, bSF, new bicingGoalTest(), bHF);


            Search search = new HillClimbingSearch();
            SearchAgent agent = new SearchAgent (problem,search);
            
            
            System.out.println();
            //printActions(agent.getActions());
            printInstrumentation(agent.getInstrumentation());
            
            bicingMapBoard ge = (bicingMapBoard) search.getGoalState();
            
            if (heuristic == 0){
            	bicingHeuristicFunction heuristicFunc = new bicingHeuristicFunction();
            	System.out.println("Cost heuristic de la solucio: " + heuristicFunc.getHeuristicValue(ge));
            }
            
            else {
            	bicingHeuristicFunction2 heuristicFunc = new bicingHeuristicFunction2();
            	System.out.println("Cost heuristic de la solucio: " + heuristicFunc.getHeuristicValue(ge));
            }


            
        } catch (Exception e) {
            System.out.println("\n exepcio ");
            e.printStackTrace();
        }
	}


    
	private static void SimulatedAnnealingSearch(bicingMapBoard mp) {
		try {
			
			Problem problem;
			HeuristicFunction bHF = null;
			if(heuristic == 0)	bHF = new bicingHeuristicFunction();
			else				bHF = new bicingHeuristicFunction2();		
			
        	
        	problem = new Problem(mp, new bicingSuccessorFunctionSA(), new bicingGoalTest(), bHF);

        	SimulatedAnnealingSearch search = new SimulatedAnnealingSearch(steps, stIter, k, lambda);
            search.traceOn();
            SearchAgent agent = new SearchAgent(problem,search);

            System.out.println();
            //printActions(agent.getActions());
            printInstrumentation(agent.getInstrumentation());
            
            bicingMapBoard ge = (bicingMapBoard) search.getGoalState();
            
            if (heuristic == 0){
            	bicingHeuristicFunction heuristicFunc = new bicingHeuristicFunction();
            	System.out.println("Cost heuristic de la solucio: " + heuristicFunc.getHeuristicValue(ge));
            }
            
            else {
            	bicingHeuristicFunction2 heuristicFunc = new bicingHeuristicFunction2();
            	System.out.println("Cost heuristic de la solucio: " + heuristicFunc.getHeuristicValue(ge));
            }
            

            
        } catch (Exception e) {
            e.printStackTrace();
        }
	}
	

    
    private static void printInstrumentation(Properties properties) {
        Iterator<Object> keys = properties.keySet().iterator();
        while (keys.hasNext()) {
            String key = (String) keys.next();
            String property = properties.getProperty(key);
            System.out.println(key + " : " + property);
        }
    }

    private static void printActions(List actions) {
        for (int i = 0; i < actions.size(); i++) {
        	//System.out.println(actions.get(i).getClass());
            String action = (String) actions.get(i);
            System.out.println("Actions");
            System.out.println(action);
        }
    }
}